package com.blyat.xsoft.kernel.component.pool;

import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * @Auther: syh
 * @Date: 2020/8/4
 * @Description:
 */
public class ConnectionProvider<T extends Connection> implements Provider<T> {
    private GenericObjectPool<T> pool;
    private URL url;

    public ConnectionProvider(URL url, Function<GenericObjectPool<T>, T> function) {
        this.url = url;
        pool = ConnectionPoolSupport.createGenericObjectPool(() -> asyncConnect(function), poolConfig());
    }

    @Override
    public T asyncConnect(Function<GenericObjectPool<T>, T> function) {
        try {
            CompletableFuture<T> future =
                    CompletableFuture.supplyAsync(() -> function.apply(this.pool));
            return future.get(url.getTimeout(), TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            throw new IllegalStateException(String.format("create connect %s error, ", url.getRemoteAddress()),  e);
        }
    }

    private <T> GenericObjectPoolConfig<T> poolConfig() {

        GenericObjectPoolConfig<T> poolConfig = new GenericObjectPoolConfig<>();

        // todo 做成可配置
        poolConfig.setMaxTotal(8); // 池中的最大连接数
        poolConfig.setMinIdle(0); // 最少的空闲连接数
        poolConfig.setMaxIdle(8); // 最多的空闲连接数
        poolConfig.setMaxWaitMillis(-1); // 当连接池资源耗尽时,调用者最大阻塞的时间,超时时抛出异常 单位:毫秒数
        poolConfig.setLifo(true); // 连接池存放池化对象方式,true放在空闲队列最前面,false放在空闲队列最后
        poolConfig.setMinEvictableIdleTimeMillis(1000L * 60L * 30L); // 连接空闲的最小时间,达到此值后空闲连接可能会被移除,默认即为30分钟
        poolConfig.setBlockWhenExhausted(true); // 连接耗尽时是否阻塞,默认为true
        return poolConfig;
    }

    @Override
    public T getPooledObject() {
        try {
            return this.pool.borrowObject();
        } catch (Exception e) {
            throw new IllegalStateException(String.format("get connect %s error, ", url.getRemoteAddress()),  e);
        }
    }
}
